﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using KinectGame;

namespace MemoGame
{
    class Game
    {
        private int gameSize = 4;

        private GameContext gameContext; 

        public int GameSize
        {
            get { return gameSize; }
            set { gameSize = value; }
        }

        private GameUI gameUI;

        public GameUI GameUI
        {
            get { return gameUI; }
            set { gameUI = value; }
        }

        public GameContext GameContext
        {
            get { return gameContext; }
            set { gameContext = value; }
        }

        private Board board;
        
        internal Board Board
        {
            get { return board; }
            set { board = value; }
        }

        private String login="Player";

        public String Login
        {
            get { return login; }
            set { login = value; }
        }
        
        private HallOfFame hallOfFame;

        internal HallOfFame HallOfFame
        {
            get { return hallOfFame; }
            set { hallOfFame = value; }
        }

        private static Game instance = null;

        public static Game getInstance()
        {
            if (instance == null)
            {
                instance = new Game();
                instance.gameSize = Options.Instance.boardSize;
                instance.login = Options.Instance.personName; 
            }
            return instance;
        }

        private static System.Timers.Timer sek;

        public static System.Timers.Timer Sek
        {
            get { return Game.sek; }
            set { Game.sek = value; }
        }

        private static DateTime time;

        public static DateTime Time
        {
            get { return Game.time; }
            set { Game.time = value; }
        }

        public void startTimer()
        {
            sek = new System.Timers.Timer(1000);
            sek.SynchronizingObject = gameUI;
            sek.Elapsed += new System.Timers.ElapsedEventHandler(sek_Tick);
            
            sek.Start();
        }

        public void stopTimer()
        {
            time = new DateTime();
            sek.Stop();
            sek.Close();
        }

        private void sek_Tick(object sender, System.Timers.ElapsedEventArgs e)
        {
            time = time.AddMilliseconds(((System.Timers.Timer)sender).Interval);
            String tt = time.ToLongTimeString();
            //Console.WriteLine("TIMER: "+tt);
 
            gameUI.updateScore(tt);

            int counter = 0;
            foreach (KeyValuePair<string, Card> c in board.Cards)
            {
                if (!c.Value.Matched)
                {
                    counter++;
                }
            }
            if (counter <= 1)
            {
                string timeSpent = time.ToLongTimeString();
                stopTimer();
                finalize(timeSpent);
            }
        }

        public KeyValuePair<string, Card> revealCard(String key, SortedDictionary<string, GameButton> buttons)
        {
            KeyValuePair<string, Card> result = new KeyValuePair<string, Card>();
            Card card = board.getField(key);
            Boolean foundOne = false;
            int counter = 0;
            foreach (KeyValuePair<string, Card> c in board.Cards)
            {
                //check how many cards are left to match
                if (!c.Value.Matched)
                {
                    counter++;
                }

                //if it founds revelead one
                if (c.Value.Revealed)
                {
                    //we check if it's the second one
                    if (card.Equals(c.Value) && !key.Equals(c.Key))
                    {
                        //reveal the card
                        card.Matched = true;
                        //reveal the pair
                        c.Value.Matched = true;
                        //so it won't be suspected again
                        c.Value.Revealed = false;
                    }
                    else
                    {
                        //hide both
                        card.Revealed = false;
                        card.Matched = false;
                        c.Value.Revealed = false;
                        c.Value.Matched = false;
                    }
                    result = c;
                    foundOne = true;
                }
            }

            if (!foundOne)
            {
                card.Revealed = true;
            }

            return result;
        }

        public KeyValuePair<string, Card> revealCard(String key)
        {
            KeyValuePair<string, Card> result = new KeyValuePair<string, Card>();
            Card card = board.getField(key);
            Boolean foundOne = false;
            int counter = 0;
            foreach (KeyValuePair<string, Card> c in board.Cards)
            {
                //check how many cards are left to match
                if (!c.Value.Matched)
                {
                    counter++;
                }

                //if it founds revelead one
                if (c.Value.Revealed)
                {
                    //we check if it's the second one
                    if (card.Equals(c.Value) && !key.Equals(c.Key))
                    {
                        //reveal the card
                        card.Matched = true;
                        //reveal the pair
                        c.Value.Matched = true;
                        //so it won't be suspected again
                        c.Value.Revealed = false;
                    }
                    else 
                    {
                        //hide both
                        card.Revealed = false;
                        card.Matched = false;
                        c.Value.Revealed = false;
                        c.Value.Matched = false;
                    }
                    result = c;
                    foundOne = true;
                }
            }

            if (!foundOne)
            {
                card.Revealed = true;
            }
            Console.WriteLine("Counter " + counter);

            return result;
        }

        private Game()
        {
            time = new DateTime();
            hallOfFame = new HallOfFame();
        }

        public Boolean initiate(int size)
        {
            gameSize = size;
            board = new Board();
            if (board.createBoard(gameSize))
            {
                gameUI = new GameUI(gameSize);
                gameUI.updatePlayer(login);
                hallOfFame.fillRanking();
                int index = GameSize;
                hallOfFame.Ranking[index].Sort();
                for (int i = 1; i <= 10; i++)
                {
                    if (hallOfFame.Ranking[index].Count < i)
                    {
                        hallOfFame.Ranking[index].Add(new HOFItem("", ""));
                    }
                }
                return true;
            }
            return false;
        }

        public void finalize(string timeSpent)
        {
            Console.WriteLine("THE END");
            this.gameContext.ApplicationMode(this.gameUI, new FinalizeDialog(timeSpent), 2); 
        }

        public void resetGame()
        {
            stopTimer();
            gameUI.Close();
            initiate(gameSize);
            gameUI = new GameUI(gameSize);
            gameUI.updatePlayer(login);
            gameUI.Show();
            startTimer();
        }

        public void inspectCard(String key)
        {
            foreach (var bb in gameUI.Buttons)
            {
                GameButton b = bb.Value;
                if (bb.Key.Equals(key))
                {
                    inspectCard(b);
                }
            }
        }

        public void inspectCard(GameButton b)
        {
            foreach (var g in board.Cards)
            {
                //get the card
                if (b.Name.Equals(g.Key))
                {
                    b.Text = "";
                    b.BackgroundImage = g.Value.Image;
                    b.Refresh();
                    Thread.Sleep(1000);
                    gameUI.refreshPanel();
                    if (g.Value.Matched || g.Value.Revealed)
                    {
                        return;
                    }
                    else //if (g.Value.Revealed)
                    {
                        KeyValuePair<string, Card> diffId = this.revealCard(g.Key);
                        if (diffId.Key != null)
                        {
                            if (diffId.Value.Id.Equals(g.Value.Id))
                            {
                                gameUI.Buttons[diffId.Key].Text = "";// diffId.Value.Id.ToString();
                                gameUI.Buttons[diffId.Key].BackgroundImage = diffId.Value.Image;
                            }
                            else
                            {
                                gameUI.Buttons[diffId.Key].Text = gameUI.Buttons[diffId.Key].Name;
                                gameUI.Buttons[diffId.Key].BackgroundImage = null;
                            }
                        }

                        if (g.Value.Matched || g.Value.Revealed)
                        {
                            b.Text = "";// g.Value.Id.ToString();
                            b.BackgroundImage = g.Value.Image;
                            //Bitmap bitmap = new Bitmap(g.Value.Filename);
                            //b.BackgroundImage = bitmap;
                        }
                        else
                        {
                            b.Text = b.Name;
                            b.BackgroundImage = null;
                        }
                    }
                }
            }
        }
        
        public void performAction(String command)
        {
            //MENU ACTIONS:
            if (command.ToLower().Equals("start") ||
                command.ToLower().Equals("start game"))
            {
                Program.MenuUI.startGame();
            }
            else if(command.ToLower().Equals("quit") ||
                command.ToLower().Equals("quit game"))
            {
                Program.MenuUI.quitGame();
            }
            else if(command.ToLower().Equals("options"))
            {
                Program.MenuUI.showOptions();
            }
            else if(command.ToLower().Equals("hall of fame"))
            {
                Program.MenuUI.showHallOfFame();
            }
            else if (command.ToLower().Equals("credits"))
            {
                Program.MenuUI.showCredits();
            }
            else //non-menu actions or noise that got in
            {
                if(command.ToLower().StartsWith("show"))
                {
                    command = command.Replace("show ", "");
                }
                Game game = Game.getInstance();
                foreach(var c in game.board.Cards)
                {
                    //checking if the command equals a key
                    if(c.Key.Equals(command))
                    {
                        inspectCard(command);
                    }
                }
            }
        }

    }
}
